package net.sureon.web;

import java.util.Iterator;
import java.util.Properties;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import net.sureon.app.AppContext;
import net.sureon.app.UserSession;
import net.sureon.biz.BizMgr;
import net.sureon.common.SureonConstants;
import net.sureon.common.exception.SureonException;
import net.sureon.common.security.Action;
import net.sureon.common.security.Privilege;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.util.AntPathMatcher;
import org.springframework.util.PathMatcher;
import org.springframework.web.context.support.WebApplicationContextUtils;
import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.servlet.handler.HandlerInterceptorAdapter;
import org.springframework.web.util.UrlPathHelper;

/**
 * execute before actually execute controllers, the handler is use for user
 * access control here.
 * 
 * @author jason
 * 
 */
public class UserPrivInterceptor extends HandlerInterceptorAdapter {
	private static final Log logger = LogFactory
			.getLog(UserPrivInterceptor.class);
	private static final String SESS_ATTR_LAST_USERID = "internal_last_userid";
	private UrlPathHelper urlPathHelper = new UrlPathHelper();
	private PathMatcher pathMatcher = new AntPathMatcher();
	private Properties urlActionMap;
	private BizMgr bizMgr;

	/**
	 * @param bizMgr
	 *            the bizMgr to set
	 */
	public void setBizMgr(BizMgr bizMgr) {
		this.bizMgr = bizMgr;
	}

	public void setUrlActionMap(Properties urlActionMap) {
		this.urlActionMap = urlActionMap;
	}

	public boolean preHandle(HttpServletRequest request,
			HttpServletResponse response, Object handler) throws Exception {

		UserSession sess = (UserSession) request.getSession().getAttribute(
				UserSession.HTTP_SESSION_KEY);

		boolean result = false;
		if (sess != null && sess.isValid()) {
			AppContext.setCurrentUserSession(sess);
			AppContext.setCurrentSpringAppContext(WebApplicationContextUtils
					.getWebApplicationContext(request.getSession()
							.getServletContext()));

			/*
			 * set the nav bar display hint.
			 */
			String navBarDisplay = (String) request.getSession().getAttribute(
					SureonConstants.NAV_BAR_DISPLAY);
			Long lastUserID = (Long) request.getSession().getAttribute(
					SESS_ATTR_LAST_USERID);
			if (navBarDisplay == null
					|| (lastUserID != null && lastUserID != AppContext
							.getUserID())) {
				boolean writeCompanyPage = Action.WriteCompany
						.probeAccess(bizMgr
								.getCategoriedObject(Privilege.COMPANY_CATEGORY));
				if (writeCompanyPage) {
					request.getSession().setAttribute(
							SureonConstants.NAV_BAR_DISPLAY,
							SureonConstants.NAV_BAR_DISPLAY_ADMIN);
				} else {
					boolean writeGroupPage = Action.WriteGroup
							.probeAccess(bizMgr
									.getCategoriedObject(Privilege.GROUP_CATEGORY));
					if (writeGroupPage) {
						request.getSession().setAttribute(
								SureonConstants.NAV_BAR_DISPLAY,
								SureonConstants.NAV_BAR_DISPLAY_GROUP);
					} else {
						request.getSession().setAttribute(
								SureonConstants.NAV_BAR_DISPLAY,
								SureonConstants.NAV_BAR_DISPLAY_MEMBER);
					}
				}
				request.getSession().setAttribute(SESS_ATTR_LAST_USERID,
						AppContext.getUserID());
			}

			/*
			 * set the session companyConfigBO if it is not there
			 */
			if(request.getSession().getAttribute(SureonConstants.SESSION_ATTR_COMPAYCONFIG) == null && AppContext.getCompanyID() > 0){
            	request.getSession().setAttribute(SureonConstants.SESSION_ATTR_COMPAYCONFIG,
    				bizMgr.getCompanyMgr().getCompanyConfig(
    						AppContext.getCompanyID()));
            }
			
			String url = urlPathHelper.getLookupPathForRequest(request);
			/*
			 * set current request URL.
			 */
			request.setAttribute(SureonConstants.REQ_ATTR_CURRENTPATH, url);
			if (logger.isDebugEnabled()) {
				logger.debug("entering:" + url);
			}
			ConfiguredAction confAction = lookupAction(url);
			if (confAction != null) {
				Action action = Action.getAction(confAction.actionName);
				if (action != null) {
					result = action.probeAccess(bizMgr
							.getCategoriedObject(confAction.category));
					if (logger.isDebugEnabled()) {
						logger.debug("checking result: " + result);
					}
				} else {
					logger.error("action name not defined, actionName:"
							+ confAction.actionName);
				}
			}
		}
		if (!result) {
			response.sendRedirect(request.getContextPath() + "/index.do");
		}
		return result;
	}

	public void postHandle(HttpServletRequest request,
			HttpServletResponse response, Object handler,
			ModelAndView modelAndView) throws Exception {
		AppContext.reset();
	}

	private ConfiguredAction lookupAction(String url) {
		String action = urlActionMap.getProperty(url);
		if (action == null) {
			String bestPathMatch = null;
			for (Iterator it = urlActionMap.keySet().iterator(); it.hasNext();) {
				String registeredPath = (String) it.next();
				if (this.pathMatcher.match(registeredPath, url)
						&& (bestPathMatch == null || bestPathMatch.length() <= registeredPath
								.length())) {
					action = urlActionMap.getProperty(registeredPath);
					bestPathMatch = registeredPath;
				}
			}
		}
		if (action != null) {
			return new ConfiguredAction(action);
		} else {
			logger.error("action not found for url:" + url);
		}
		return null;
	}

	private static class ConfiguredAction {
		private String actionName;
		private int category;

		private ConfiguredAction(String configuredActionName) {
			if (logger.isDebugEnabled()) {
				logger.debug("action:" + configuredActionName);
			}
			String[] splits = configuredActionName.split(",");
			actionName = splits[0];
			category = Integer.parseInt(splits[1].trim());
		}
	}
}